import os
import shutil
import tkinter as tk
from tkinter import filedialog
from tkinter.ttk import Progressbar
from tkinter import messagebox
from datetime import datetime
# from exif import Image
import exifread  # 替换为更可靠的exifread库
import ctypes
try:
    import pyi_splash
    pyi_splash.close()
except:
    pass
def create_window(title, width=350, height=180):
    """
    创建一个基本的 GUI 窗口
    :param title: 窗口标题
    :param width: 窗口宽度，默认为 350
    :param height: 窗口高度，默认为 180
    :return: 创建的窗口
    """
    # 调用api设置成由应用程序缩放
    ctypes.windll.shcore.SetProcessDpiAwareness(1)
    # 调用api获得当前的缩放因子
    ScaleFactor = ctypes.windll.shcore.GetScaleFactorForDevice(0)

    # 创建窗口对象
    window = tk.Tk()

    # 设置窗口标题
    window.title(title)

    # 设置窗口大小和位置
    window.geometry(f"{int(width*ScaleFactor/100)}x{int(height*ScaleFactor/100)}+{int(window.winfo_screenwidth()/2 - width/2)}+{int(window.winfo_screenheight()/2 - height/2)}")

    # 设置窗口大小不可变
    window.resizable(False, False)

    # 隐藏最大最小化按钮
    # window.attributes("-toolwindow", True)

    # 设置背景颜色
    window["background"] = "steelblue"

    # 设置透明度
    # window.attributes("-alpha", 0.8)

    return window

def create_entry(parent, width=30):
    """
    创建一个输入框
    :param parent: 父控件
    :param width: 宽度，默认为 30
    :return: 创建的输入框
    """
    entry = tk.Entry(parent, width=width)
    return entry

def create_button(parent, text, command):
    """
    创建一个按钮
    :param parent: 父控件
    :param text: 按钮文本
    :param command: 点击按钮的回调函数
    :return: 创建的按钮
    """
    button = tk.Button(parent, text=text, command=command)
    return button

def classify_image(filename, dest_dir):
    """
    将指定图片移动到相应的分类文件夹中
    :param filename: 图片文件名
    :param dest_dir: 目标文件夹路径
    """
    # 读取图片 exif 中的创建日期，如果不存在则将图片分类到“无exif”文件夹中
    date_obj = filename.split("\\")[-1].split(".")[0]
    dest_subdir = "无exif"
    try:
        # 使用exifread读取EXIF数据（更可靠的库）
        with open(filename, 'rb') as f:
            # 读取所有EXIF标签（details=False减少冗余数据）
            tags = exifread.process_file(f, details=False, stop_tag='EXIF DateTimeOriginal')
            
            # 优先查找拍摄时间标签（按优先级排序）
            exif_tags = [
                'EXIF DateTimeOriginal',  # 最常用的拍摄时间标签
                'Image DateTime',         # 图像创建时间（可能被修改）
                'EXIF DateTimeDigitized'  # 数字化时间（通常与拍摄时间一致）
            ]
            
            for tag in exif_tags:
                if tag in tags:
                    date_str = str(tags[tag])
                    # 解析EXIF标准日期格式（YYYY:MM:DD HH:MM:SS）
                    try:
                        date_obj = datetime.strptime(date_str, "%Y:%m:%d %H:%M:%S")
                        dest_subdir = date_obj.strftime("%Y-%m-%d")
                        break  # 找到有效时间后退出循环
                    except (ValueError, TypeError):
                        date_obj = filename.split("\\")[-1].split(".")[0]
                        dest_subdir = "无exif"
                        continue  # 格式错误则尝试下一个标签

    except Exception as e:
        print(f"读取图片 {filename} 的 exif 时出错：{str(e)}")

    print(dest_subdir)

    # 创建目标子文件夹（如果不存在）
    if '-' in dest_subdir:
        year_dir, month_dir, date_dir = dest_subdir.split('-')
        year_dir += '年'
        month_dir += '月'
        date_dir += '日'
        if not os.path.exists(os.path.join(dest_dir, year_dir)):
                os.makedirs(os.path.join(dest_dir, year_dir))
        if not os.path.exists(os.path.join(dest_dir, year_dir, year_dir+month_dir)):
            os.makedirs(os.path.join(dest_dir, year_dir, year_dir+month_dir))
        if not os.path.exists(os.path.join(dest_dir, year_dir, year_dir+month_dir, year_dir+month_dir+date_dir)):
            os.makedirs(os.path.join(dest_dir, year_dir, year_dir+month_dir, year_dir+month_dir+date_dir))
        dest_subdir_path = os.path.join(dest_dir, year_dir, year_dir+month_dir, year_dir+month_dir+date_dir)
        date_conut[year_dir + month_dir + date_dir] = date_conut.get(year_dir + month_dir + date_dir, 0) + 1
    else:
        dest_subdir_path = os.path.join(dest_dir, dest_subdir)
        if not os.path.exists(dest_subdir_path):
            os.makedirs(dest_subdir_path)
        date_conut[dest_subdir] = date_conut.get(dest_subdir, 0) + 1

    # 移动或复制图片到目标子文件夹中，并决定是否按日期重命名
    # 如果文件已存在,则询问用户是否覆盖,如果用户选择覆盖,则直接覆盖,如果用户选择保留,则自动重命名,如果用户选择取消,则跳过此文件

    img_name, img_ext = os.path.splitext(os.path.basename(filename))
    
    if rename_flag.get():
        new_name_base = str(date_obj).replace(":", "_").replace(" ", "_")
    else:
        new_name_base = img_name

    dest_file_path = os.path.join(dest_subdir_path, new_name_base + img_ext)

    if os.path.exists(dest_file_path):
        response = messagebox.askquestion(
            "文件冲突",
            f"文件已存在：\n{dest_file_path}\n\n"
            "选择处理方式：\n"
            "✔ 是：覆盖原文件\n"
            "✔ 否：保留两个（自动重命名）\n"
            "✔ 取消：跳过此文件",
            parent=root,
            type=messagebox.YESNOCANCEL
        )

        if response == 'yes':
            try:
                os.remove(dest_file_path)
            except Exception as e:
                messagebox.showerror("错误", f"无法删除原文件以覆盖：{e}")
                return
        elif response == 'no':
            counter = 1
            while os.path.exists(dest_file_path):
                new_name = f"{new_name_base}_{counter}"
                dest_file_path = os.path.join(dest_subdir_path, new_name + img_ext)
                counter += 1
        else:
            return  # 跳过文件

    try:
        if move_flag.get():
            shutil.move(filename, dest_file_path)
        else:
            shutil.copy2(filename, dest_file_path)
    except Exception as e:
        messagebox.showerror("操作失败", f"处理文件时出错：\n{filename}\n错误：{e}")

def traverse_images(root_dir, dest_dir):
    """
    遍历指定目录下所有图片，并将它们分类到相应的文件夹中
    :param root_dir: 指定目录
    :param dest_dir: 目标文件夹
    """
    file_paths = []
    for root, dirs, files in os.walk(root_dir):
        for file_name in files:
            if file_name.lower().endswith((".jpg", ".jpeg", ".png", ".bmp", ".gif")):
                file_path = os.path.join(root, file_name)
                file_paths.append(file_path)
    return file_paths

def browse_folder():
    """
    使用 filedialog 打开文件夹选择对话框
    """
    src_dir = filedialog.askdirectory()
    if src_dir:
        entry_src.delete(0, tk.END)
        entry_src.insert(0, src_dir)

def browse_dest_folder():
    """
    使用 filedialog 打开目标文件夹选择对话框
    """
    dest_dir = filedialog.askdirectory()
    if dest_dir:
        entry_dest.delete(0, tk.END)
        entry_dest.insert(0, dest_dir)

def start_classification():
    """
    开始对指定目录下的图片进行分类
    """
    src_dir = entry_src.get()
    dest_dir = entry_dest.get()
    print(dest_dir)
    if not os.path.exists(src_dir):
        print(f"指定的遍历目录 {src_dir} 不存在！")
        messagebox.showerror(title='警告', message=f"指定的遍历目录 {src_dir} 不存在！")
        return
    if not os.path.exists(dest_dir):
        print(f"指定的目标文件夹 {dest_dir} 不存在！")
        messagebox.showerror(title='警告', message=f"指定的目标文件夹 {dest_dir} 不存在！")
        return
    file_paths = traverse_images(src_dir, dest_dir)

    progressbar['maximum'] = len(file_paths)  # 设置进度条最大值为文件总数
    for idx, file_path in enumerate(file_paths, 1):
        classify_image(file_path, dest_dir)
        progressbar['value'] = idx  # 更新进度条的位置为已处理的文件数量
        root.update()  # 更新tk界面
    pic_sort_info = ''
    for date, count in date_conut.items():
        pic_sort_info += date + '有' + str(count) + '张图片'+ '\t'
    date_conut.clear()
    print("图片分类完成！")
    print(pic_sort_info)
    messagebox.showinfo(title="图片分类完成！", message=pic_sort_info if pic_sort_info else '一共分类共0张图片')
    

def open_explorer():
    if os.path.exists(entry_dest.get()):
        os.startfile('"' + entry_dest.get() + '"')
    else:
        messagebox.showerror(title='警告', message='无法打开目标文件夹！')

if __name__ == '__main__':
    # 创建dict用于统计不同日期的图片数
    date_conut = dict()

    # 创建主窗口
    root = create_window("照片分类")

    # 创建输入框和按钮
    entry_src = create_entry(root)
    button_browse_src = create_button(root, "选择遍历目录", browse_folder)

    entry_dest = create_entry(root)
    button_browse_dest = create_button(root, "选择目标文件夹", browse_dest_folder)

    button_start = create_button(root, "开始分类", start_classification)

    button_open_explorer = create_button(root, "打开目标文件夹", open_explorer)
    # 布局输入框和按钮
    entry_src.grid(row=1, column=1, columnspan=2, padx=10, pady=10)
    entry_dest.grid(row=2, column=1, columnspan=2, padx=10, pady=10)
    button_browse_src.grid(row=1, column=3, pady=10, sticky="nsew")
    button_browse_dest.grid(row=2, column=3, pady=10, sticky="nsew")
    button_start.grid(row=3, column=3, pady=10, sticky="nsew")
    button_open_explorer.grid(row=5, column=2, pady=10, sticky="nse")

    # 创建复选框变量并设置默认状态 (0表示未选中，1表示选中)
    move_flag = tk.IntVar(value=0)
    rename_flag = tk.IntVar(value=0)

    # 创建复选框实例并绑定到变量
    cb1 = tk.Checkbutton(root, text="仅移动", variable=move_flag)
    cb2 = tk.Checkbutton(root, text="按时间重命名", variable=rename_flag)

    # 设置复选框显示位置
    cb1.grid(row=3, column=1)
    cb2.grid(row=3, column=2)

    # 创建进度条
    progressbar = Progressbar(root, length=666, mode='determinate', orient='horizontal')
    progressbar.grid(row=4, column=1, columnspan=3, padx=15, pady=10)  # 显示进度条

    # 运行主循环
    root.mainloop()
